<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace Fendx\Annotation;

use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\Common\Annotations\DocParser;
use Fendx\Aop\Ast;
use Fendx\Di\ReflectionManager;
use Symfony\Component\Finder\Finder;

class Scanner
{
    /**
     * @var Ast
     */
    private $parser;

    public function __construct(array $ignoreAnnotations = ['mixin'])
    {
        $this->parser = new Ast();

        // TODO: this method is deprecated and will be removed in doctrine/annotations 2.0
        AnnotationRegistry::registerLoader('class_exists');

        foreach ($ignoreAnnotations as $annotation) {
            AnnotationReader::addGlobalIgnoredName($annotation);
        }
    }

    public function scan(array $paths): array
    {
        if (! $paths) {
            return [];
        }

        $paths = $this->normalizeDir($paths);

        $finder = new Finder();
        $finder->files()->in($paths)->name('*.php');

        $metas = [];
        foreach ($finder->getIterator() as $file) {
            try {
                $stmts = $this->parser->parse($file->getContents());
                $className = $this->parser->parseClassByStmts($stmts);
                if (! $className) {
                    continue;
                }
                $metas[$className] = $stmts;
            } catch (\RuntimeException $e) {
                continue;
            }
        }

        return $metas;
    }

/*    private function getClassNames(string $dir) {
        $finder = new Finder();
        $finder->files()->in($dir)->name('*.php');

        $parser =  new \Fendx\Aop\Ast();

        $classNames = [];
        foreach ($finder as $file) {
            try {
                $stmts = $parser->parse($file->getContents());
                $className = $parser->parseClassByStmts($stmts);
                if (! $className) {
                    continue;
                }
                $classNames[] = $className;
            } catch (\RuntimeException $e) {
                continue;
            }
        }
        return $classNames;
    }*/

//    private function getAnnotations(string $className) {
//
//        // Deprecated and will be removed in 2.0 but currently needed
//
//        $reflectionClass = new \ReflectionClass($className);
////$property = $reflectionClass->get('index');
////        var_export($property);
//
//        $methods = $reflectionClass->getMethods();
//
//        $reader = new AnnotationReader();
//        $myClassAnnotation = $reader->getClassAnnotations(
//            $reflectionClass
//        );
//        if (empty($myClassAnnotation)) {
//            return [];
//        }
//
//        $reader = new AnnotationReader();
//        $myMethodAnnotations = [];
//        foreach ($methods as $method) {
//            $myMethodAnnotations[] = $reader->getMethodAnnotations(
//                $method
//            );
//        }
//
//        return [
//            'class' => $myClassAnnotation,
//            'methods' => $myMethodAnnotations,
//        ];
//    }






    public function parserClass($classCollection)
    {
        $parser = new DocParser();
        $parser->setIgnoreNotImportedAnnotations(true);
        $reader = new AnnotationReader($parser);

        $results = [];
        // Because the annotation class should loaded before use it, so load file via $finder previous, and then parse annotation here.
        foreach ($classCollection as $className) {
            $reflectionClass = ReflectionManager::reflectClass($className);
            $classAnnotations = $reader->getClassAnnotations($reflectionClass);

            // Parse methods annotations.
            $methods = $reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC);
            $allMethodAnnotations = [];
            foreach ($methods as $method) {
                $methodAnnotations = $reader->getMethodAnnotations($method);
                $allMethodAnnotations[$method->name] = $methodAnnotations ?? [];
            }
            if (!empty($classAnnotations) && !empty($allMethodAnnotations)) {
                $results[$className] = [
                    'name' => $className,
                    'class' => $classAnnotations,
                    'methods' => $allMethodAnnotations,
                ];
            }
        }
        return $results;
    }

    /**
     * Normalizes given directory names by removing directory not exist.
     */
    public function normalizeDir(array $paths): array
    {
        $result = [];
        foreach ($paths as $path) {
            if (is_dir($path)) {
                $result[] = $path;
            }
        }

        return $result;
    }
}
